#pragma once

#include "hlog.h"
#include "hloop.h"
#include <algorithm>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <dirent.h>
#include <sys/stat.h>

struct FileInfo {
    std::string filename;
    std::string fullPath;
    time_t lastModifiedTime;
    uint64_t size;

    FileInfo(const std::string& fname, const std::string& fpath, time_t mtime, uint64_t fsize)
      : filename(fname)
      , fullPath(fpath)
      , lastModifiedTime(mtime)
      , size(fsize) {}
};

class DirectoryCleaner {
public:
    DirectoryCleaner(const std::string& dirPath, uint64_t thresholdGB)
      : m_dirPath(dirPath)
      , m_thresholdBytes(thresholdGB * 1024ULL * 1024ULL * 1024ULL) {}

    static std::string formatFileSize(uint64_t bytes) {
        const char* units[] = {"B", "KB", "MB", "GB", "TB"};
        int unitIndex       = 0;
        double size         = bytes;

        while (size >= 1024 && unitIndex < 4) {
            size /= 1024;
            unitIndex++;
        }

        std::stringstream ss;
        ss << std::fixed << std::setprecision(2) << size << " " << units[unitIndex];
        return ss.str();
    }

    static std::string formatTime(time_t time) {
        char buffer[80];
        struct tm* timeinfo = localtime(&time);
        strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", timeinfo);
        return std::string(buffer);
    }

    void cleanOldFiles() {
        std::vector<FileInfo> files;
        uint64_t totalSize = 0;

        if (!scanDirectory(files, totalSize)) {
            return;
        }

        if (totalSize > m_thresholdBytes) {
            // 按修改时间排序
            std::sort(files.begin(), files.end(), [](const FileInfo& a, const FileInfo& b) {
                return a.lastModifiedTime < b.lastModifiedTime;
            });

            uint64_t deleteSize = totalSize - m_thresholdBytes;
            uint64_t freedSize  = 0;

            for (const auto& file : files) {
                if (freedSize >= deleteSize) break;

                if (removeFile(file)) {
                    freedSize += file.size;

                    hlogi("Deleted: %s (%s), Modified: %s",
                          file.filename.c_str(),
                          formatFileSize(file.size).c_str(),
                          formatTime(file.lastModifiedTime).c_str());
                }
            }
        }
    }

private:
    bool scanDirectory(std::vector<FileInfo>& files, uint64_t& totalSize) {
        DIR* dir = opendir(m_dirPath.c_str());
        if (!dir) {
            hloge("Error opening directory: %s", m_dirPath.c_str());
            return false;
        }

        struct dirent* entry;
        while ((entry = readdir(dir)) != NULL) {
            std::string filename = entry->d_name;
            if (filename == "." || filename == "..") continue;

            std::string fullPath = m_dirPath + "/" + filename;
            struct stat fileStat;

            if (stat(fullPath.c_str(), &fileStat) == 0) {
                // 只处理普通文件
                if (S_ISREG(fileStat.st_mode)) {
                    files.emplace_back(filename, fullPath, fileStat.st_mtime, fileStat.st_size);
                    totalSize += fileStat.st_size;
                }
            }
        }

        closedir(dir);
        return true;
    }

    bool removeFile(const FileInfo& file) {
        if (remove(file.fullPath.c_str()) != 0) {
            hloge("Error deleting file: : %s", file.fullPath.c_str());
            return false;
        }
        return true;
    }

    std::string m_dirPath;
    uint64_t m_thresholdBytes;
};
